const fsp = require("fs/promises");
const path = require("path");

// ====================== 用于 main 函数 ==========================

// 生成 ini 配置文件模板

async function createConfigIni () {
  const configContent = `
; ================================================
; Darkest Dungeon Mod 工具配置文件
; 修改此文件以自定义源目录和目标目录等设置
; 注意：
; - 路径分隔符请使用双反斜杠 "\\\\" 或 单斜杠 "/"
;   单反斜杠 '\\' 会转义后面的首字母，造成未知错误
; - 修改后请先保存，然后重新运行程序
; ================================================

; 是否启用 NSFW 内容（true/false）
useNSFW = false

; 是否创建新的 mods 目录，保留并备份旧目录（true/false）
CreNewModDir = true

; 文件夹前缀（默认为 sn_）
folderPrefix = sn_

; Steam Workshop 创意工坊完整路径（精确到含创意工坊 ID 的文件夹）
; 通常是 盘符:/SteamLibrary/steamapps/workshop/content/262060
sourceDir =

; 目标路径（精确到游戏根目录下的 mods 文件夹）
; 通常是 盘符:/SteamLibrary/steamapps/common/DarkestDungeon/mods
targetDir =
`.trim();
  // 确定输出路径
  const configFilePath = path.resolve(ROOT_DIR, 'config.ini');
  // 写入文件
  try {
    await fsp.writeFile(configFilePath, configContent, 'utf-8');
    console.log(`已成功生成配置文件到：${configFilePath}`);
  } catch (err) {
    console.error(`写入配置文件失败:`, err.message);
  }
}

// ====================== 用于 fileList 函数 ==========================

async function done (data, log, fn) {
  // console.log(data, log, fn);
  if (typeof fn === 'function') try { await fn(); } catch (err) { console.error(err); }
  // 异步更新modfiles.txt
  try {
    return await updateModFilesTxt(data.path, `\x1b[33m[${data.newFolderName}]\x1b[0m ${log}`);
  } catch (updateErr) { console.error('更新modfiles.txt失败:', updateErr); }
}

// 有用于更新 modfiles.txt 的函数
async function updateModFilesTxt (modPath, log) {
  try {
    // 获取所有文件路径
    const files = await collectFiles(modPath);

    // 排序（可选）
    files.sort((a, b) => a.path.localeCompare(b.path));

    // 生成modfiles.txt内容
    const modFilesContent = files
    .map(file => `${file.path} ${file.size}`)
    .join('\n');

    // 写入modfiles.txt
    await fsp.writeFile(path.join(modPath, 'modfiles.txt'), modFilesContent, 'utf8');

    return log + '\x1b[32m[MODFILES]\x1b[0m modfiles.txt已更新';
  } catch (error) {
    console.error(`[MODFILES] Fix Error: ${modPath}\n`, error);
    return log + '\x1b[31m[MODFILES]\x1b[0m 更新modfiles.txt时发生错误\n';
  }
}
// 收集所有文件的递归函数
async function collectFiles (modPath) {
  const files = [];

  async function walkDir (currentPath) {
    try {
      const items = await fsp.readdir(currentPath, { withFileTypes: true });

      for (const item of items) {
        const fullPath = path.join(currentPath, item.name);
        const relativePath = path.relative(modPath, fullPath).replace(/\\/g, '/');

        // 忽略steam_workshop_upload.exe.lnk等特殊文件
        if (item.name === 'steam_workshop_upload.exe.lnk') continue;

        if (item.isDirectory()) {
          await walkDir(fullPath); // 如果是目录，递归遍历
        } else {
          try {
            const stats = await fsp.stat(fullPath);
            files.push({ path: relativePath, size: stats.size });
          } catch (err) {
            console.error(`无法获取文件信息 ${fullPath}:`, err);
          }
        }
      }
    } catch (err) {
      console.error(`无法读取路径 ${currentPath}:`, err);
    }
  }

  await walkDir(modPath);
  return files;
}

async function jsonModif (filePath, fn) {
  if (!Array.isArray(filePath)) return console.error("jsonModif: 'filePath' is not an Array.")
  if (typeof fn != 'function') return console.error("jsonModif: 'fn' is not a Function.")
  const target = path.resolve(...filePath)

  try {
    const jsonData = await fsp.readFile(target, 'utf8');
    const json = JSON.parse(jsonData);
    // 调用模拟 await jsonModif([...path], (json, save) => { json.foo=bar; save() })
    const result = fn(json);
    if (result) await fsp.writeFile(target, JSON.stringify(result, null, 2), 'utf8');
    // 继续处理...
  } catch (err) {
    console.error('[jsonModif] 读取或解析文件失败:', err);
  } finally {
    // 显式释放变量
    jsonData = null;
    json = null;
  }
}

// ====================== Darkest 文件处理相关函数 ==========================

/**
 * 解析 .darkest 文件为结构化对象
 * @param {string} filePath 文件路径
 * @returns {Object} 结构化数据
 */
async function parseDarkestFile (filePath) {
  const content = await fsp.readFile(filePath, 'utf8');
  const lines = content.split('\n').map(line => line.trim());

  const result = {};
  let currentType = null;
  let currentObj = {};

  for (let line of lines) {
    if (!line || line.startsWith('#')) continue;

    // 匹配类型声明如: inventory_item:
    const typeMatch = line.match(/^(\w+):/);
    if (typeMatch) {
      if (currentType && Object.keys(currentObj).length > 0) {
        if (!result[currentType]) result[currentType] = [];
        result[currentType].push(currentObj);
      }

      currentType = typeMatch[1];
      currentObj = {};
    }

    processDarkestFields(line, currentObj);
    //   // 提取该行中的字段
    //   const fields = line.replace(/^[\w\d_]+:/, '').trim().split(/\s+/);
    //   processDarkestFields(fields, currentObj);
    // } else {
    //   const fields = line.trim().split(/\s+/);
    //   processDarkestFields(fields, currentObj);
    // }
  }

  // 添加最后一个对象
  if (currentType && Object.keys(currentObj).length > 0) {
    if (!result[currentType]) result[currentType] = [];
    result[currentType].push(currentObj);
  }

  return result;
}

/**
 * 处理一行中的所有字段并填充到对象
 * @param {string} line 行字符串
 * @param {Object} obj 当前对象
 */
function processDarkestFields (line, obj, order) {
  // 匹配所有 .key "value" 或 .key value 格式字段
  const regex = /\.([a-zA-Z_][\w.]*)\s+("[^"]+"|\S+)/g;
  let match;

  if (!obj['$']) obj['$'] = [];

  while ((match = regex.exec(line)) !== null) {
    const key = `.${match[1]}`;
    let value = match[2];
    // console.log(key, value);
    // 如果是引号包裹的字符串，去掉引号
    if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
      value = value.slice(1, -1);
    }

    // 判断布尔值
    if (value.toLowerCase() === 'true') {
      value = true;
    } else if (value.toLowerCase() === 'false') {
      value = false;
    }
    // 判断整数
    else if (/^-?\d+$/.test(value)) {
      value = parseInt(value, 10);
    }
    // 空值处理
    // else if (value === '') {
    //   value = undefined;
    // }

    obj[key] = value;
    obj['$'].push(key);
  }
}

/**
 * 将结构化对象写回 .darkest 文件
 * @param {Object} data 数据对象
 * @param {string} filePath 文件路径
 */
async function writeDarkestFile (data, filePath) {
  let output = '';

  for (const type in data) {
    const entries = data[type];

    for (const entry of entries) {
      const keys = entry['$'] ? entry['$'].filter(key => key !== '$') : Object.keys(entry).filter(k => k !== '$');
      const lineParts = keys.map(key => {
        let val = entry[key];
        if (typeof val === 'string') {
          // 如果值中包含空格或特殊字符，加引号
          if (/[\s"\\]/.test(val)) {
            val = `"${val.replace(/"/g, '\\"')}"`;
          } else {
            val = `"${val}"`;
          }
        } else if (typeof val === 'boolean') {
          val = val ? 'true' : 'false';
        } else {
          val = val.toString();
        }
        return `${key} ${val}`;
      });

      output += `${type}: ${lineParts.join('   ')}\n`; // 多个空格美化
    }
  }

  await fsp.writeFile(filePath, output, 'utf8');
}

/**
 * 修改 .darkest 文件内容的函数（类似 jsonModif）
 * @param {string[]} filePath 文件路径数组，例如 ['mods', 'sn_011', 'file.darkest']
 * @param {Function} fn 修改函数，接收 parsedData 并返回新的数据
 */
async function darkestModif (filePath, fn) {
  if (!Array.isArray(filePath)) {
    return console.error("darkestModif: 'filePath' is not an Array.");
  }
  if (typeof fn !== 'function') {
    return console.error("darkestModif: 'fn' is not a Function.");
  }

  const target = path.resolve(...filePath);

  try {
    const parsedData = await parseDarkestFile(target);
    // console.log(target)
    const result = fn(parsedData)
    if (!result) return console.error("[darkestModif] 未得到有效的返回值类型");
    const modifiedData = result;
    if (modifiedData) {
      await writeDarkestFile(modifiedData, target);
      console.log(`✅ 已成功修改并写回文件: ${target}`);
    }
  } catch (err) {
    console.error(`[darkestModif] 处理文件失败: ${target}`, err.message || err);
  } finally {
    // 显式释放变量
    parsedData = null;
    modifiedData = null;
  }
}

// 导出需要用到的方法
module.exports = {
  createConfigIni,
  done, jsonModif,
  darkestModif
}
